/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://gitee.com/newgolo/embedme.git
 * Copyright 2014~2020 @ ShenZhen ,China
*******************************************************************************/
#ifndef __MQTT_CLIENT_H__
#define __MQTT_CLIENT_H__

#include <iostream> 
#include <memory>
extern "C"{
#include "mqttclient.h"
}
#include "libemb/BaseType.h"
/**
 * @file MqttClient.h
 * @brief MQTT客户端
 * 
 */
namespace libembx{
using namespace std;
using namespace libemb;
enum QOS_MQTT_E{
	QOS_ONCE_MOST=0,/**< QOS0:至多1次,可能丢失 */
	QOS_ONCE_LEAST,	/**< QOS1:至少1次,确保到达,可能重复 */
	QOS_ONCE_ONLY	/**< QOS2:只有1次,确保到达,没有重复 */
};

class MqttClientProxy{
DECL_CLASSNAME("MqttClientProxy")
using MqttMsgHandler = void(*)(void*,message_data_t*);
public:
	MqttClientProxy();
	~MqttClientProxy();
	/**
	 * @brief 默认的接收消息方法
	 * @param topic 消息主题
	 * @param msg 	消息内容
	 */
	virtual void onRecvMsg(const std::string& topic, const std::string& msg);
protected:
	bool keepAlive();
	bool setWillOption(const std::string& topic,const std::string& msg, int qos, bool retained);
	bool open(std::string clientID,int maxMsgSize,std::string username="", std::string password="");
	bool connect(const std::string& server,std::string certificate="");
	bool subscribe(const std::string& topic,int qos,MqttMsgHandler handler);
	bool publish(const std::string& topic,const std::string& msg, int qos);
	bool unsubscribe(const std::string& topic);	
	bool disconnect();
	bool close();
	
private:
	mqtt_client_t* m_client{nullptr};
	std::string m_clientID;
	std::string m_username;
	std::string m_password;
	std::string m_server;
	std::string m_port;
	std::string m_certificate;
};

class MqttClientProxy;
template <class T>
/* MqttClientAdapter是一个单例模板类,可以使用DECL_INSTANCE宏 */
class MqttClientAdapter:public MqttClientProxy{
DECL_CLASSNAME(MqttClientAdapter)
public:
	static T& getInstance()
	{
		static T instance;
		return instance;
	}
	virtual ~MqttClientAdapter(){};
	/**
	 * @brief 保持心跳
	 * @return true 执行成功
	 * @return false 执行失败
	 */
	bool keepAlive()
	{
		return MqttClientProxy::keepAlive();
	}
	/**
	 * @brief 设置遗言
	 * @param topic 遗愿主题 
	 * @param msg 遗愿消息
	 * @param qos 遗愿qos
	 * @param retained 是否保存
	 * @return true 设置成功
	 * @return false 设置失败
	 */
	bool setWillOption(const std::string& topic,const std::string& msg, int qos, bool retained)
	{
		return MqttClientProxy::setWillOption(topic, msg, qos, retained);
	}
	/**
	 * @brief 打开客户端
	 * @param clientID 客户端ID,最长64字节
	 * @param username 用户名
	 * @param password 密码
	 * @return true 打开成功
	 * @return false 打开失败
	 */
	bool open(std::string clientID, int maxMsgSize, std::string username="", std::string password="")
	{
		return MqttClientProxy::open(clientID,maxMsgSize,username,password);
	}
	/**
	 * @brief 连接代理服务器
	 * @param server 代理服务器地址(格式为"url:port")
	 * @param certificate 安全证书
	 * @return true 连接成功
	 * @return false 连接失败
	 */
	bool connect(const std::string& server,std::string certificate="")
	{	
		return MqttClientProxy::connect(server, certificate);
	}
	/**
	 * @brief 订阅消息
	 * @param topic 消息主题
	 * @param qos 服务质量
	 * @return true 订阅成功
	 * @return false 订阅失败
	 */
	bool subscribe(const std::string& topic,int qos)
	{
		return MqttClientProxy::subscribe(topic, qos,&(T::handleMessage));
	}
	/**
	 * @brief 发布消息
	 * @param topic 消息主题
	 * @param msg 消息内容
	 * @param qos 服务质量
	 * @return true 发布成功
	 * @return false 发布失败
	 */
	bool publish(const std::string& topic,const std::string& msg, int qos)
	{
		return MqttClientProxy::publish(topic, msg, qos);
	}
	/**
	 * @brief 取消订阅
	 * @param topic 消息主题
	 * @return true 取消订阅成功
	 * @return false 取消订阅失败
	 */
	bool unsubscribe(const std::string& topic)
	{
		return MqttClientProxy::unsubscribe(topic);
	}
	/**
	 * @brief 断开与代理服务器的连接
	 * @return true 断开连接成功
	 * @return false 断开连接失败
	 */
	bool disconnect()
	{
		return MqttClientProxy::disconnect();
	}
	/**
	 * @brief 关闭客户端
	 * @return true 关闭成功
	 * @return false 关闭失败
	 */
	bool close()
	{
		return MqttClientProxy::close();
	}
private:
	static void handleMessage(void* client, message_data_t* msg)
	{
		T::getInstance().onRecvMsg(std::string(msg->topic_name),std::string((const char*)(msg->message->payload),msg->message->payloadlen));
	}
protected:
	MqttClientAdapter(){};
	MqttClientAdapter(const MqttClientAdapter&)=delete;
	MqttClientAdapter& operator=(const MqttClientAdapter&)=delete;	
};
}
#endif
